package com.skyline.courier.net.provider.netty;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;

import java.net.SocketAddress;

import com.skyline.courier.net.AbstractClient;
import com.skyline.courier.net.Connection;

public class NettyClient extends AbstractClient {
	private Bootstrap bootstrap;
	private int workerThreads = -1;
	private NioEventLoopGroup workerLoopGroup;
	
	public void setWorkerThreads(int workerThreads) {
		this.workerThreads = workerThreads;
	}
	
	@Override
	protected void doStart() {
		initEventLoopGroup();
		initBootstrap();
	}

	@Override
	protected void doClose() {
		workerLoopGroup.shutdownGracefully();
		bootstrap = null;
	}
	
	private void initBootstrap() {
		bootstrap = new Bootstrap();
		bootstrap.group(workerLoopGroup);
		bootstrap.channel(NioSocketChannel.class);
		
		bootstrap.option(ChannelOption.TCP_NODELAY, getTcpNoDelay());
		bootstrap.option(ChannelOption.SO_KEEPALIVE, getKeepAlive());
		bootstrap.option(ChannelOption.SO_REUSEADDR, getReuseAddress());
		bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, getConnectTimeout());
		
		NettyClientInitializer initializer = new NettyClientInitializer();
		initializer.setSerializer(getSerializer());
		initializer.setReadIdleTime(getReadIdleTime());
		initializer.setWriteIdleTime(getWriteIdleTime());
		initializer.setStatistic(statistic);
		initializer.setConnectionManager(connectionManager);
		bootstrap.handler(initializer);
	}

	private void initEventLoopGroup() {
		if(workerThreads == -1) {
			workerLoopGroup = new NioEventLoopGroup();
		} else {
			workerLoopGroup = new NioEventLoopGroup(workerThreads);
		}
	}

	@Override
	protected Connection doGetConnection(SocketAddress address) {
		NettyConnection connection = new NettyConnection(bootstrap);
		connection.doConnect(address);
		return connection;
	}

}
